package com.wondertek.service.service.sys.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wondertek.common.enums.StatusEnum;
import com.wondertek.common.exception.AppException;
import com.wondertek.common.util.base.PoiUtil;
import com.wondertek.common.util.security.SecurityUtil;
import com.wondertek.service.dto.sys.req.*;
import com.wondertek.service.dto.sys.res.SysUserExportRes;
import com.wondertek.service.dto.sys.res.SysUserRes;
import com.wondertek.service.entity.business.UserSitePo;
import com.wondertek.service.entity.sys.SysRolePo;
import com.wondertek.service.entity.sys.SysUserDepartPo;
import com.wondertek.service.entity.sys.SysUserPo;
import com.wondertek.service.entity.sys.SysUserRolePo;
import com.wondertek.service.mapper.sys.SysUserMapper;
import com.wondertek.service.service.business.UserSiteService;
import com.wondertek.service.service.sys.*;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author xqs
 */
@Slf4j
@Service("sysUserService")
@RequiredArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUserPo> implements ISysUserService {
    private final ISysRoleService sysRoleService;
    private final ISysUserRoleService sysUserRoleService;
    private final ISysUserDepartService userDepartService;
    private final ISysDepartService departService;
    private final SysUserMapper sysUserMapper;
    //    private final PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    @Lazy
    @Resource
    private ISysAuthService sysAuthService;

    @Resource
    private UserSiteService userSiteService;

    @Resource
    private ISysFileService sysFileService;

    /*
     * 邮箱获取验证码
     * */
    @Override
    public long checkEmail(String email) {
        LambdaQueryWrapper<SysUserPo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUserPo::getEmail, email);
        wrapper.eq(SysUserPo::getStatus, StatusEnum.ENABLE.getCode());
        return this.count(wrapper);
    }

    /*
     * 忘记密码-修改密码
     * */
    @Override
    public void forgetAndRestPassword(SysUserForgetReq passwordReq) {
        SysUserPo user = lambdaQuery().eq(SysUserPo::getEmail, passwordReq.getEmail())
                .eq(SysUserPo::getStatus, StatusEnum.ENABLE.getCode()).one();
        user.setPassword(BCrypt.hashpw(passwordReq.getPassword()));
        this.updateById(user);
    }

    @Override
    public Page<SysUserRes> page(SysUserQueryReq sysUserQueryReq) {
        Page<SysUserRes> page = sysUserMapper.page(new Page<>(sysUserQueryReq.getPageNo(),
                sysUserQueryReq.getPageSize()), sysUserQueryReq);
        page.setRecords(page.getRecords().stream().peek(v -> {
            v.setPassword(null);
            v.setAvatarUrl(sysFileService.getViewFile(v.getAvatar()));
        }).collect(Collectors.toList()));
        return page;
    }

    /**
     * 用户导出
     *
     * @param sysUserQueryReq
     */
    @Override
    public void export(SysUserQueryReq sysUserQueryReq, HttpServletResponse response) {

        if (sysUserQueryReq.getIds() != null && !sysUserQueryReq.getIds().isEmpty()) {
            SysUserQueryReq req = new SysUserQueryReq();
            req.setIds(sysUserQueryReq.getIds());
            sysUserQueryReq = req;
        }

        List<SysUserRes> page = sysUserMapper.page(sysUserQueryReq);

        List<SysUserExportRes> res = new ArrayList<>();

        for (SysUserRes r : page) {
            SysUserExportRes sysUserExportRes = new SysUserExportRes();
            sysUserExportRes.setNickname(r.getNickname());
            sysUserExportRes.setEmail(r.getEmail());
            sysUserExportRes.setStatus(r.getStatus());

            List<SysRolePo> rolePoList = r.getRolePoList();
            if (rolePoList != null && !rolePoList.isEmpty()) {
                String roles = "";
                for (int i = 0; i < rolePoList.size(); i++) {
                    roles += rolePoList.get(i).getRoleName();
                    if (i != rolePoList.size() - 1)
                        roles += ", ";
                }
                sysUserExportRes.setRoles(roles);
            }

            res.add(sysUserExportRes);
        }

        PoiUtil.writeExcelToResponse("员工管理", SysUserExportRes.class, res, response);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(SysUserAddReq sysUserAddReq) {
        if (this.lambdaQuery().eq(SysUserPo::getEmail, sysUserAddReq.getEmail()).count() > 0) {
            throw new AppException("email.repeat");
        }
        if (this.lambdaQuery().eq(SysUserPo::getMobile, sysUserAddReq.getMobile()).count() > 0) {
            throw new AppException("phone.repeat");
        }
        //保存用户
        SysUserPo sysUserPo = new SysUserPo();
        BeanUtil.copyProperties(sysUserAddReq, sysUserPo);
        sysUserPo.setPassword(BCrypt.hashpw(sysUserPo.getPassword()));
        this.save(sysUserPo);
        //保存用户角色关联关系
        saveUserRole(sysUserPo.getId(), sysUserAddReq.getRoleIds());
        //保存用户部门关联关系
        saveUserDepart(sysUserPo.getId(), sysUserAddReq.getDepartIds());
        //建立站点用户关系
        if (CollectionUtils.isNotEmpty(sysUserAddReq.getSiteIds())) {
            userSiteService.insertBatch(sysUserPo.getId(), sysUserAddReq.getSiteIds());
        }
    }

    private void saveUserRole(String id, Set<String> roleIds) {
        //先删除旧的用户角色关联
        LambdaQueryWrapper<SysUserRolePo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUserRolePo::getUserId, id);
        sysUserRoleService.getBaseMapper().delete(queryWrapper);
        Set<SysUserRolePo> userRolePos = roleIds.stream().map(var -> {
            SysUserRolePo sysUserRole = new SysUserRolePo();
            sysUserRole.setUserId(id);
            sysUserRole.setRoleId(var);
            return sysUserRole;
        }).collect(Collectors.toSet());
        sysUserRoleService.saveBatch(userRolePos);
    }

    private void saveUserDepart(String id, Set<String> departIds) {
        //先删除旧的用户角色关联
        LambdaQueryWrapper<SysUserDepartPo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUserDepartPo::getUserId, id);
        userDepartService.getBaseMapper().delete(queryWrapper);
        if (departIds != null && departIds.size() > 0) {
            Set<SysUserDepartPo> userDepartPos = departIds.stream().map(var -> {
                SysUserDepartPo sysUserDepartPo = new SysUserDepartPo();
                sysUserDepartPo.setUserId(id);
                sysUserDepartPo.setDepartId(var);
                return sysUserDepartPo;
            }).collect(Collectors.toSet());
            userDepartService.saveBatch(userDepartPos);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(SysUserUpdateReq sysUserUpdateReq) {
        String id = sysUserUpdateReq.getId();
        SysUserPo sysUserPo = this.getById(id);
        if (sysUserPo == null) {
            throw new AppException("user.not.exist");
        }
        if (!StrUtil.equals(sysUserPo.getEmail(), sysUserUpdateReq.getEmail())) {
            if (this.lambdaQuery().eq(SysUserPo::getEmail, sysUserUpdateReq.getEmail()).count() > 0) {
                throw new AppException("email.repeat");
            }
        }
        if (!StrUtil.equals(sysUserPo.getMobile(), sysUserUpdateReq.getMobile())) {
            if (this.lambdaQuery().eq(SysUserPo::getMobile, sysUserUpdateReq.getMobile()).count() > 0) {
                throw new AppException("phone.repeat");
            }
        }
        BeanUtil.copyProperties(sysUserUpdateReq, sysUserPo);
        //保存用户
        this.lambdaUpdate().set(SysUserPo::getEmail, sysUserUpdateReq.getEmail())
                .set(SysUserPo::getMobile, sysUserUpdateReq.getMobile())
                .set(SysUserPo::getCountryCode, sysUserUpdateReq.getCountryCode())
                .set(SysUserPo::getNickname, sysUserUpdateReq.getNickname())
                .set(SysUserPo::getAvatar, sysUserUpdateReq.getAvatar())
                .eq(SysUserPo::getId, id).update();
        //保存用户角色关联关系
        saveUserRole(id, sysUserUpdateReq.getRoleIds());
        //保存用户部门关联关系
        saveUserDepart(sysUserPo.getId(), sysUserUpdateReq.getDepartIds());
        //建立站点用户关系

        userSiteService.remove(new LambdaQueryWrapper<UserSitePo>().eq(UserSitePo::getUserId, sysUserPo.getId()));
        if (CollectionUtils.isNotEmpty(sysUserUpdateReq.getSiteIds())) {
            userSiteService.insertBatch(sysUserPo.getId(), sysUserUpdateReq.getSiteIds());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void disable(String userId) {
        SysUserPo userPo = this.getById(userId);
        if (ObjectUtil.isNotEmpty(userPo) && StrUtil.equals("admin", userPo.getNickname())) {
            throw new AppException("user.internal.not.operate");
        }
        userPo.setStatus(StatusEnum.DISABLE.getCode());
        this.updateById(userPo);
        //下线用户
        sysAuthService.cleanToken(userPo.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void enable(String userId) {
        SysUserPo userPo = this.getById(userId);
        userPo.setStatus(StatusEnum.ENABLE.getCode());
        this.updateById(userPo);
    }

    @Override
    public List<SysUserRes> findUserByParam(List<String> departIds, List<String> roleCodes, List<Integer> departTypes, String userId) {
        Map<String, Object> map = new HashMap<>();
        map.put("departIds", departIds);
        map.put("roleCodes", roleCodes);
        map.put("departTypes", departTypes);
        map.put("userId", userId);
        return sysUserMapper.findUserByParam(map);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePassword(SysUserUpdatePasswordReq updatePasswordReq) {
        String userId = SecurityUtil.getLoginUser().getUserId();
        SysUserPo sysUserPo = this.getById(userId);
        if (!BCrypt.checkpw(updatePasswordReq.getOldPassword(), sysUserPo.getPassword())) {
            throw new AppException("old.password.error");
        }
        sysUserPo.setPassword(BCrypt.hashpw(updatePasswordReq.getNewPassword()));
        this.updateById(sysUserPo);
        //下线用户
        sysAuthService.cleanToken(sysUserPo.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void restPassword(SysUserRestPasswordReq restPasswordReq) {
        SysUserPo userPo = this.getById(restPasswordReq.getUserId());
        userPo.setPassword(BCrypt.hashpw(restPasswordReq.getNewPassword()));
        this.updateById(userPo);
        //下线用户
        sysAuthService.cleanToken(userPo.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(String id) {
        SysUserPo sysUserPo = this.getById(id);

        if (ObjectUtil.isNotEmpty(sysUserPo) && StrUtil.equals("admin", sysUserPo.getNickname())) {
            throw new AppException("user.internal.not.operate");
        }

        if (ObjectUtil.isNotEmpty(sysUserPo) && sysUserPo.getStatus().equals(StatusEnum.ENABLE.getCode())) {
            throw new AppException("user.enable.not.delete");
        }

        //取消之前用户关联的部门
        LambdaQueryWrapper<SysUserDepartPo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUserDepartPo::getUserId, id);
        userDepartService.getBaseMapper().delete(wrapper);
        //取消之前用户关联的站点
        LambdaQueryWrapper<UserSitePo> siteWrapper = new LambdaQueryWrapper<>();
        siteWrapper.eq(UserSitePo::getUserId, id);
        userSiteService.getBaseMapper().delete(siteWrapper);
        //取消之前用户关联的角色
        LambdaQueryWrapper<SysUserRolePo> roleWrapper = new LambdaQueryWrapper<>();
        roleWrapper.eq(SysUserRolePo::getUserId, id);
        sysUserRoleService.getBaseMapper().delete(roleWrapper);
        // 删除用户
        this.removeById(id);
    }
}
